import {ComponentPropsType} from "../../components/QuestionComponents";
import {produce} from "immer";
import {createSlice, nanoid, PayloadAction} from "@reduxjs/toolkit";
import {getNextSelectedId, insertNewComponent} from "./utils";
import cloneDeep from 'lodash.clonedeep'
import {arrayMove} from "@dnd-kit/sortable";

export type ComponentsInfoType = {
    fe_id: string
    type: string
    title: string
    isHidden?: boolean
    isLocked?: boolean
    props: ComponentPropsType
}

export type ComponentsStateType = {
    selectedId: string
    componentList: Array<ComponentsInfoType>
    copiedComponent: ComponentsInfoType | null
}
const INIT_STATE: ComponentsStateType = {
    selectedId: '',
    componentList: [],
    copiedComponent: null
}

export const componentsSlice = createSlice({
    name: 'components',
    initialState: INIT_STATE,
    reducers: {
        resetComponents: (state: ComponentsStateType, action: PayloadAction<ComponentsStateType>) => {
            return action.payload
        },
        changeSelectId: produce((draft: ComponentsStateType, action: PayloadAction<string>) => {
            draft.selectedId = action.payload
        }),
        addComponent: produce((draft: ComponentsStateType, action: PayloadAction<ComponentsInfoType>) => {
            const newComponent = action.payload
            insertNewComponent(draft, newComponent)
        }),
        changeComponentProps: produce((draft: ComponentsStateType, action: PayloadAction<{
            fe_id: string;
            newProps: ComponentPropsType
        }>) => {
            const {fe_id, newProps} = action.payload
            const curComp = draft.componentList.find(c => c.fe_id === fe_id)
            if (curComp) {
                curComp.props = {
                    ...curComp.props,
                    ...newProps
                }
            }
        }),
        removeSelectedComponent: produce((draft: ComponentsStateType) => {
            const {componentList = [], selectedId: removedId} = draft
            draft.selectedId = getNextSelectedId(removedId, componentList)
            const index = componentList.findIndex(item => item.fe_id === removedId)
            componentList.splice(index, 1)
        }),
        changeComponentHidden: produce((draft: ComponentsStateType, action: PayloadAction<{
            fe_id: string,
            isHidden: boolean
        }>) => {
            const {componentList = []} = draft;
            const {fe_id, isHidden} = action.payload
            let newSelectedId = ''
            if (isHidden) {
                newSelectedId = getNextSelectedId(fe_id, componentList)
            } else {
                newSelectedId = fe_id
            }
            draft.selectedId = newSelectedId
            const curComp = componentList.find(c => c.fe_id === fe_id)
            if (curComp) {
                curComp.isHidden = isHidden
            }
        }),
        toggleComponentLocked: produce((draft: ComponentsStateType, action: PayloadAction<{
            fe_id: string,
        }>) => {
            const {fe_id} = action.payload
            const curComp = draft.componentList.find(c => c.fe_id === fe_id)
            if (curComp) {
                curComp.isLocked = !curComp.isLocked
            }
        }),
        copySelectedComponent: produce((draft: ComponentsStateType) => {
            const {selectedId, componentList = []} = draft
            const selectedComponent = componentList.find(c => c.fe_id === selectedId)
            if (selectedComponent == null) return
            draft.copiedComponent = cloneDeep(selectedComponent)
        }),
        pasteCopiedComponent: produce((draft: ComponentsStateType) => {
            const {copiedComponent} = draft
            if (copiedComponent == null) return
            copiedComponent.fe_id = nanoid()
            insertNewComponent(draft, copiedComponent)
        }),
        selectPrevComponent: produce((draft: ComponentsStateType) => {
            const {selectedId, componentList = []} = draft
            const selectedIndex = componentList.findIndex(item => item.fe_id === selectedId)
            if (selectedIndex < 0) return
            if (selectedIndex <= 0) return;
            draft.selectedId = componentList[selectedIndex - 1].fe_id
        }),
        selectNextComponent: produce((draft: ComponentsStateType) => {
            const {selectedId, componentList = []} = draft
            const selectedIndex = componentList.findIndex(item => item.fe_id === selectedId)
            if (selectedIndex < 0) return
            if (selectedIndex >= componentList.length - 1) return;
            draft.selectedId = componentList[selectedIndex + 1].fe_id
        }),
        changeComponentTitle: produce((draft: ComponentsStateType, action: PayloadAction<{
            fe_id: string;
            title: string
        }>) => {
            const {fe_id, title} = action.payload
            const {componentList} = draft
            const curComp = componentList.find(c => c.fe_id === fe_id)
            if (curComp) curComp.title = title
        }),
        moveComponent: produce((draft: ComponentsStateType, action: PayloadAction<{
            oldIndex: number;
            newIndex: number;
        }>) => {
            const {componentList: curComponentList} = draft
            const {oldIndex, newIndex} = action.payload
            draft.componentList = arrayMove(curComponentList, oldIndex, newIndex)
        }),
    }
})

export const {
    resetComponents,
    changeSelectId,
    addComponent,
    changeComponentProps,
    removeSelectedComponent,
    changeComponentHidden,
    toggleComponentLocked,
    copySelectedComponent,
    pasteCopiedComponent,
    selectPrevComponent,
    selectNextComponent,
    changeComponentTitle,
    moveComponent
} = componentsSlice.actions;

export default componentsSlice.reducer